home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / IP.C < prev    next >
Text File  |  1993-08-09  |  13KB  |  492 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  */
  5. #include "global.h"
  6. #include "mbuf.h"
  7. #include "timer.h"
  8. #include "internet.h"
  9. #include "netuser.h"
  10. #include "iface.h"
  11. #include "pktdrvr.h"
  12. #include "ip.h"
  13. #include "icmp.h"
  14.  
  15. static struct mbuf * near fraghandle __ARGS((struct ip *ip,struct mbuf *bp));
  16. static void ip_timeout __ARGS((void *arg));
  17. static void near free_reasm __ARGS((struct reasm *rp));
  18. static void near freefrag __ARGS((struct frag *fp));
  19. static struct reasm * near lookup_reasm __ARGS((struct ip *ip));
  20. static struct reasm * near creat_reasm __ARGS((struct ip *ip));
  21. static struct frag * near newfrag __ARGS((int16 offset,int16 last,struct mbuf *bp));
  22.  
  23. struct mib_entry Ip_mib[20] = {
  24.     "",                    0,
  25.     "Forwarding",        1,
  26.     "DefaultTTL",        MAXTTL,
  27.     "InReceives",        0,
  28.     "InHdrErrors",        0,
  29.     "InAddrErrors",        0,
  30.     "ForwDatagrams",    0,
  31.     "InUnknownProtos",    0,
  32.     "InDiscards",        0,
  33.     "InDelivers",        0,
  34.     "OutRequests",        0,
  35.     "OutDiscards",        0,
  36.     "OutNoRoutes",        0,
  37.     "ReasmTimeout",        TLB,
  38.     "ReasmReqds",        0,
  39.     "ReasmOKs",            0,
  40.     "ReasmFails",        0,
  41.     "FragOKs",            0,
  42.     "FragFails",        0,
  43.     "FragCreates",        0,
  44. };
  45.  
  46. struct reasm *Reasmq = NULLREASM;
  47. static struct raw_ip *Raw_ip = NULLRIP;
  48.  
  49. #define    INSERT    0
  50. #define    APPEND    1
  51. #define    PREPEND    2
  52.  
  53. /* Send an IP datagram. Modeled after the example interface on p 32 of
  54.  * RFC 791
  55.  */
  56. int
  57. ip_send(
  58. int32 source,            /* source address */
  59. int32 dest,                /* Destination address */
  60. char protocol,            /* Protocol */
  61. char tos,                /* Type of service */
  62. char ttl,                /* Time-to-live */
  63. struct mbuf *bp,        /* Data portion of datagram */
  64. int16 length,            /* Optional length of data portion */
  65. int16 id,                /* Optional identification */
  66. char df)                /* Don't-fragment flag */
  67. {
  68.     struct mbuf *tbp;
  69.     struct ip ip;            /* Pointer to IP header */
  70.     static int16 id_cntr;    /* Datagram serial number */
  71.     struct phdr phdr;
  72.  
  73.     ipOutRequests++;
  74.  
  75.     if(source == INADDR_ANY)
  76.         source = locaddr(dest);
  77.     if(length == 0 && bp != NULLBUF)
  78.         length = len_p(bp);
  79.     if(id == 0)
  80.         id = id_cntr++;
  81.     if(ttl == 0)
  82.         ttl = ipDefaultTTL;
  83.  
  84.     /* Fill in IP header */
  85.     ip.version = IPVERSION;
  86.     ip.tos = tos;
  87.     ip.length = IPLEN + length;
  88.     ip.id = id;
  89.     ip.flags.mf = ip.flags.congest = ip.optlen = ip.offset = 0;
  90.     ip.flags.df = df;
  91.     ip.ttl = ttl;
  92.     ip.protocol = protocol;
  93.     ip.source = source;
  94.     ip.dest = dest;
  95.     tbp = htonip(&ip,bp,0);
  96.     bp = pushdown(tbp,sizeof(struct phdr));
  97.  
  98.     if(ismyaddr(ip.dest)) {
  99.         /* Pretend it has been sent by the loopback interface before
  100.          * it appears in the receive queue
  101.          */
  102.         phdr.iface = &Loopback;
  103.         Loopback.ipsndcnt++;
  104.         Loopback.rawsndcnt++;
  105.         Loopback.lastsent = secclock();
  106.     } else {
  107.         phdr.iface = NULLIF;
  108.     }
  109.     phdr.type = CL_NONE;
  110.     memcpy(bp->data,(char *)&phdr,sizeof(struct phdr));
  111.     enqueue(&Hopper,bp);
  112.     return 0;
  113. }
  114.  
  115. /* Reassemble incoming IP fragments and dispatch completed datagrams
  116.  * to the proper transport module
  117.  */
  118. void
  119. ip_recv(
  120. struct iface *iface,    /* Incoming interface */
  121. struct ip *ip,            /* Extracted IP header */
  122. struct mbuf *bp,        /* Data portion */
  123. int rxbroadcast)        /* True if received on subnet broadcast address */
  124. {
  125.     /* Function to call with completed datagram */
  126.     struct raw_ip *rp;
  127.     struct mbuf *bp1, *tbp;
  128.     int rxcnt = 0;
  129.     struct iplink *ipp;
  130.  
  131.     /* If we have a complete packet, call the next layer
  132.      * to handle the result. Note that fraghandle passes back
  133.      * a length field that does NOT include the IP header
  134.      */
  135.     if((bp = fraghandle(ip,bp)) == NULLBUF)
  136.         /* Not done yet */
  137.         return;
  138.  
  139.     ipInDelivers++;
  140.  
  141.     for(rp = Raw_ip; rp != NULLRIP; rp = rp->next) {
  142.         if(rp->protocol != ip->protocol)
  143.             continue;
  144.         rxcnt++;
  145.         /* Duplicate the data portion, and put the header back on */
  146.         dup_p(&bp1,bp,0,len_p(bp));
  147.         if(bp1 != NULLBUF) {
  148.             tbp = htonip(ip,bp1,1);
  149.             enqueue(&rp->rcvq,tbp);
  150.             if(rp->r_upcall != NULLVFP)
  151.                 (*rp->r_upcall)(rp);
  152.         } else {
  153.             free_p(bp1);
  154.         }
  155.     }
  156.     /* Look it up in the transport protocol table */
  157.     for(ipp = Iplink;ipp->funct != NULL;ipp++){
  158.         if(ipp->proto == ip->protocol)
  159.             break;
  160.     }
  161.     if(ipp->funct != NULL){
  162.         /* Found, call transport protocol */
  163.         (*ipp->funct)(iface,ip,bp,rxbroadcast);
  164.     } else {
  165.         /* Not found */
  166.         if(rxcnt == 0) {
  167.             /* Send an ICMP Protocol Unknown response... */
  168.             ipInUnknownProtos++;
  169.             /* ...unless it's a broadcast */
  170.             if(!rxbroadcast) {
  171.                 icmp_output(ip,bp,ICMP_DEST_UNREACH,ICMP_PROT_UNREACH,NULLICMP);
  172.             }
  173.         }
  174.         free_p(bp);
  175.     }
  176. }
  177.  
  178. /* Handle IP packets encapsulated inside IP */
  179. void
  180. ipip_recv(
  181. struct iface *iface,        /* Incoming interface */
  182. struct ip *ip,                /* Extracted IP header */
  183. struct mbuf *bp,            /* Data portion */
  184. int rxbroadcast)            /* True if received on subnet broadcast address */
  185. {
  186.     struct phdr phdr;
  187.     struct mbuf *tbp = pushdown(bp,sizeof(struct phdr));
  188.  
  189.     bp = tbp;
  190.     phdr.iface = &Encap;
  191.     phdr.type = CL_NONE;
  192.     memcpy(bp->data,(char *)&phdr,sizeof(struct phdr));
  193.     enqueue(&Hopper,bp);
  194. }
  195.  
  196. /* Process IP datagram fragments
  197.  * If datagram is complete, return it with ip->length containing the data
  198.  * length (MINUS header); otherwise return NULLBUF
  199.  */
  200. static struct mbuf * near
  201. fraghandle(
  202. struct ip *ip,                /* IP header, host byte order */
  203. struct mbuf *bp)            /* The fragment itself */
  204. {
  205.     struct frag *lastfrag = NULLFRAG, *nextfrag, *tfp;
  206.     struct mbuf *tbp;
  207.     int16 i;
  208.  
  209.     /* Index of first byte beyond fragment */
  210.     int16 last = ip->offset + ip->length - (IPLEN + ip->optlen);
  211.  
  212.     /* Pointer to reassembly descriptor */
  213.     struct reasm *rp = lookup_reasm(ip);
  214.  
  215.     if(ip->offset == 0 && !ip->flags.mf) {
  216.         /* Complete datagram received. Discard any earlier fragments */
  217.         if(rp != NULLREASM) {
  218.             free_reasm(rp);
  219.             ipReasmOKs++;
  220.         }
  221.         return bp;
  222.     }
  223.     ipReasmReqds++;
  224.  
  225.     /* First fragment; create new reassembly descriptor */
  226.     if(rp == NULLREASM && (rp = creat_reasm(ip)) == NULLREASM) {
  227.         /* No space for descriptor, drop fragment */
  228.         ipReasmFails++;
  229.         free_p(bp);
  230.         return NULLBUF;
  231.     }
  232.     /* Keep restarting timer as long as we keep getting fragments */
  233.     stop_timer(&rp->timer);
  234.     start_timer(&rp->timer);
  235.  
  236.     /* If this is the last fragment, we now know how long the
  237.      * entire datagram is; record it
  238.      */
  239.     if(!ip->flags.mf)
  240.         rp->length = last;
  241.  
  242.     /* Set nextfrag to the first fragment which begins after us,
  243.      * and lastfrag to the last fragment which begins before us
  244.      */
  245.     for(nextfrag = rp->fraglist; nextfrag != NULLFRAG; nextfrag = nextfrag->next) {
  246.         if(nextfrag->offset > ip->offset)
  247.             break;
  248.         lastfrag = nextfrag;
  249.     }
  250.     /* Check for overlap with preceeding fragment */
  251.     if(lastfrag != NULLFRAG  && ip->offset < lastfrag->last) {
  252.         /* Strip overlap from new fragment */
  253.         i = lastfrag->last - ip->offset;
  254.         pullup(&bp,NULLCHAR,i);
  255.         if(bp == NULLBUF)
  256.             return NULLBUF;    /* Nothing left */
  257.         ip->offset += i;
  258.     }
  259.     /* Look for overlap with succeeding segments */
  260.     for(; nextfrag != NULLFRAG; nextfrag = tfp) {
  261.         tfp = nextfrag->next;    /* save in case we delete fp */
  262.  
  263.         if(nextfrag->offset >= last)
  264.             break;    /* Past our end */
  265.         /* Trim the front of this entry; if nothing is
  266.          * left, remove it.
  267.          */
  268.         i = last - nextfrag->offset;
  269.         pullup(&nextfrag->buf,NULLCHAR,i);
  270.  
  271.         if(nextfrag->buf == NULLBUF){
  272.             /* superseded; delete from list */
  273.             if(nextfrag->prev != NULLFRAG)
  274.                 nextfrag->prev->next = nextfrag->next;
  275.             else
  276.                 rp->fraglist = nextfrag->next;
  277.             if(tfp->next != NULLFRAG)
  278.                 nextfrag->next->prev = nextfrag->prev;
  279.             freefrag(nextfrag);
  280.         } else {
  281.             nextfrag->offset = last;
  282.         }
  283.     }
  284.     /* Lastfrag now points, as before, to the fragment before us;
  285.      * nextfrag points at the next fragment. Check to see if we can
  286.      * join to either or both fragments.
  287.      */
  288.     i = INSERT;
  289.  
  290.     if(lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  291.         i |= APPEND;
  292.  
  293.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  294.         i |= PREPEND;
  295.  
  296.     switch(i){
  297.     case INSERT:            /* Insert new desc between lastfrag and nextfrag */
  298.         tfp = newfrag(ip->offset,last,bp);
  299.         tfp->prev = lastfrag;
  300.         tfp->next = nextfrag;
  301.         if(lastfrag != NULLFRAG)
  302.             lastfrag->next = tfp;            /* Middle of list */
  303.         else
  304.             rp->fraglist = tfp;                /* First on list */
  305.         if(nextfrag != NULLFRAG)
  306.             nextfrag->prev = tfp;
  307.         break;
  308.     case APPEND:                            /* Append to lastfrag */
  309.         append(&lastfrag->buf,bp);
  310.         lastfrag->last = last;                /* Extend forward */
  311.         break;
  312.     case PREPEND:                            /* Prepend to nextfrag */
  313.         tbp = nextfrag->buf;
  314.         nextfrag->buf = bp;
  315.         append(&nextfrag->buf,tbp);
  316.         nextfrag->offset = ip->offset;        /* Extend backward */
  317.         break;
  318.     case (APPEND|PREPEND):
  319.         /* Consolidate by appending this fragment and nextfrag
  320.          * to lastfrag and removing the nextfrag descriptor */
  321.         append(&lastfrag->buf,bp);
  322.         append(&lastfrag->buf,nextfrag->buf);
  323.         nextfrag->buf = NULLBUF;
  324.         lastfrag->last = nextfrag->last;
  325.  
  326.         /* Finally unlink and delete the now unneeded nextfrag */
  327.         lastfrag->next = nextfrag->next;
  328.         if(nextfrag->next != NULLFRAG)
  329.             nextfrag->next->prev = lastfrag;
  330.         freefrag(nextfrag);
  331.         break;
  332.     }
  333.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG
  334.       && rp->length != 0){
  335.         /* We've gotten a complete datagram, so extract it from the
  336.          * reassembly buffer and pass it on.
  337.          */
  338.         bp = rp->fraglist->buf;
  339.         rp->fraglist->buf = NULLBUF;
  340.         /* Tell IP the entire length */
  341.         ip->length = rp->length + (IPLEN + ip->optlen);
  342.         free_reasm(rp);
  343.         ipReasmOKs++;
  344.         return bp;
  345.     } else {
  346.         return NULLBUF;
  347.     }
  348. }
  349.  
  350. /* Arrange for receipt of raw IP datagrams */
  351. struct raw_ip *
  352. raw_ip(int protocol,void (*r_upcall)())
  353. {
  354.     struct raw_ip *rp = mxallocw(sizeof(struct raw_ip));
  355.  
  356.     rp->protocol = protocol;
  357.     rp->r_upcall = r_upcall;
  358.  
  359.     rp->next = Raw_ip;
  360.     Raw_ip = rp;
  361.  
  362.     return rp;
  363. }
  364.  
  365. /* Free a raw IP descriptor */
  366. void
  367. del_ip(struct raw_ip *rpp)
  368. {
  369.     struct raw_ip *rp, *rplast = NULLRIP;
  370.  
  371.     /* Do sanity check on arg */
  372.     for(rp = Raw_ip; rp != NULLRIP; rplast = rp, rp = rp->next)
  373.         if(rp == rpp)
  374.             break;
  375.  
  376.     if(rp == NULLRIP)
  377.         return;    /* Doesn't exist */
  378.  
  379.     /* Unlink */
  380.     if(rplast != NULLRIP)
  381.         rplast->next = rp->next;
  382.     else
  383.         Raw_ip = rp->next;
  384.  
  385.     /* Free resources */
  386.     free_q(&rp->rcvq);
  387.     xfree(rp);
  388. }
  389.  
  390. static struct reasm * near
  391. lookup_reasm(struct ip *ip)
  392. {
  393.     struct reasm *rp, *rplast = NULLREASM;
  394.  
  395.     for(rp = Reasmq; rp != NULLREASM; rplast = rp, rp = rp->next){
  396.         if(ip->id == rp->id
  397.           && ip->source == rp->source
  398.           && ip->dest == rp->dest
  399.           && ip->protocol == rp->protocol) {
  400.             if(rplast != NULLREASM) {
  401.                 /* Move to top of list for speed */
  402.                 rplast->next = rp->next;
  403.                 rp->next = Reasmq;
  404.                 Reasmq = rp;
  405.             }
  406.             return rp;
  407.         }
  408.     }
  409.     return NULLREASM;
  410. }
  411.  
  412. /* Create a reassembly descriptor,
  413.  * put at head of reassembly list
  414.  */
  415. static struct reasm * near
  416. creat_reasm(struct ip *ip)
  417. {
  418.     struct reasm *rp = mxallocw(sizeof(struct reasm));
  419.  
  420.     rp->source = ip->source;
  421.     rp->dest = ip->dest;
  422.     rp->id = ip->id;
  423.     rp->protocol = ip->protocol;
  424.     rp->timer.func = ip_timeout;
  425.     rp->timer.arg = rp;
  426.     set_timer(&rp->timer,ipReasmTimeout * 1000L);
  427.  
  428.     rp->next = Reasmq;
  429.     Reasmq = rp;
  430.  
  431.     return rp;
  432. }
  433.  
  434. /* Free all resources associated with a reassembly descriptor */
  435. static void near
  436. free_reasm(struct reasm *r)
  437. {
  438.     struct reasm *rp, *rplast = NULLREASM;
  439.     struct frag *fp;
  440.  
  441.     for(rp = Reasmq; rp != NULLREASM; rplast = rp, rp = rp->next)
  442.         if(r == rp)
  443.             break;
  444.  
  445.     if(rp == NULLREASM)
  446.         return;    /* Not on list */
  447.  
  448.     /* Remove from list of reassembly descriptors */
  449.     if(rplast != NULLREASM)
  450.         rplast->next = rp->next;
  451.     else
  452.         Reasmq = rp->next;
  453.  
  454.     stop_timer(&rp->timer);
  455.  
  456.     /* Free any fragments on list, starting at beginning */
  457.     while((fp = rp->fraglist) != NULLFRAG){
  458.         rp->fraglist = fp->next;
  459.         free_p(fp->buf);
  460.         xfree(fp);
  461.     }
  462.     xfree(rp);
  463. }
  464.  
  465. /* Handle reassembly timeouts by deleting all reassembly resources */
  466. static void
  467. ip_timeout(void *arg)
  468. {
  469.     free_reasm((struct reasm *)arg);
  470.     ipReasmFails++;
  471. }
  472.  
  473. /* Create a fragment */
  474. static struct frag * near
  475. newfrag(int16 offset,int16 last,struct mbuf *bp)
  476. {
  477.     struct frag *fp = mxallocw(sizeof(struct frag));
  478.  
  479.     fp->buf = bp;
  480.     fp->offset = offset;
  481.     fp->last = last;
  482.     return fp;
  483. }
  484.  
  485. /* Delete a fragment, return next one on queue */
  486. static void near
  487. freefrag(struct frag *fp)
  488. {
  489.     free_p(fp->buf);
  490.     xfree(fp);
  491. }
  492.